package org.wenhuayuan.uilibrary.hiitem

import android.content.Context
import android.util.SparseArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import java.lang.ref.WeakReference
import java.lang.reflect.ParameterizedType
import java.util.*

open class HiAdapter(context: Context): RecyclerView.Adapter<ViewHolder>(){
    private var recyclerViewRef: WeakReference<RecyclerView>? = null
    private var context: Context? = null
    private var mInflater: LayoutInflater? = null // 加载布局的
    private var dataSets = ArrayList<HiDataItem<*, ViewHolder>>()
    // 装载列表中不同视图的itemType的集合
    private var typeArrays = SparseArray<HiDataItem<*, ViewHolder>>()

    private val headers = SparseArray<View>()
    private val footers = SparseArray<View>()

    init {
        this.context = context
        this.mInflater = LayoutInflater.from(context)
    }

    // 定义HeaderView的viewType的基准值
    // headers.put(index, view) 其中index使用view的viewType
    private var BASE_ITEM_TYPE_HEADER = 100000
    private var BASE_ITEM_TYPE_FOOTER = 200000

    fun addHeaderView(view: View) {
        if (headers.indexOfValue(view) < 0) {
            // 表示 没有添加过header
            headers.put(BASE_ITEM_TYPE_HEADER++, view)
            notifyItemInserted(headers.size() - 1)
        }
    }
    fun removeHeaderView(view: View) {
        val indexValue = headers.indexOfValue(view)
        if (indexValue < 0) return
        headers.removeAt(indexValue)
        notifyItemRemoved(indexValue)
    }
    fun addFooterView(view: View) {
        if (footers.indexOfValue(view) < 0) {
            // 表示 没有添加过footer
            footers.put(BASE_ITEM_TYPE_FOOTER++, view)
            notifyItemInserted(itemCount)
        }
    }
    fun removeFooterView(view: View) {
        val indexValue = footers.indexOfValue(view)
        if (indexValue < 0) return
        footers.removeAt(indexValue)
        notifyItemRemoved(indexValue + getHeaderSize() + getOriginalItemSize())
    }

    private fun getHeaderSize():Int{
        return headers.size()
    }
    private fun getFooterSize():Int{
        return footers.size()
    }
    private fun getOriginalItemSize():Int{
        return dataSets.size
    }

    /**
     * 向adapter当中去注册列表当中不同的HiDataItem
     * notify: 要不要对列表去刷新
     */
    fun addItem(index: Int, item: HiDataItem<*, ViewHolder>, notify: Boolean) {
        if(index > 0) {
            // 大于零，表示想要在指定的位置添加
            dataSets.add(index, item)
        } else {
            dataSets.add(item)
        }

        if (notify) {
            val notifyPos = if (index > 0) index else dataSets.size - 1
            notifyItemInserted(notifyPos)
        }


    }
    fun addItems(items: List<HiDataItem<*, ViewHolder>>, notify: Boolean) {
        val start = dataSets.size
        for (item in items) {
            dataSets.add(item)
        }
        if (notify) {
            notifyItemRangeInserted(start, items.size)
        }
    }
    fun refreshItem(hiDataItem: HiDataItem<*, out ViewHolder>) {
        val index = dataSets.indexOf(hiDataItem)
        notifyItemChanged(index)
    }

    fun removeItem(index: Int): HiDataItem<*, out ViewHolder>? {
        return if (index > 0 && index < dataSets.size) {
            val remove= dataSets.removeAt(index)
            notifyItemRemoved(index)
            remove
        } else {
            null
        }
    }
    fun removeItem(item : HiDataItem<*, out ViewHolder>) {
        val index = dataSets.indexOf(item)
        removeItem(index)
    }


    // 返回列表中每个item视图的类型
    override fun getItemViewType(position: Int): Int {

        if (isHeaderPosition(position)) {
            // 表示item是header类型
            return headers.keyAt(position)
        }
        if (isFooterPosition(position)) {
            // 表示item是footer类型
            // footer的位置就必须要计算一下
            val footPos = position - getHeaderSize() - getOriginalItemSize()
            return footers.keyAt(footPos)
        }

        // 表示 item既不是header也不是footer类型
        val itemPos = position - getHeaderSize()
        val dataItem = dataSets[itemPos]
        val type = dataItem.javaClass.hashCode()
        // 如果没有包含这种类型的item，则添加进来
        if (typeArrays.indexOfKey(type) < 0) {
            typeArrays.put(type, dataItem)
        }
        return type
    }

    private fun isFooterPosition(position: Int): Boolean {
        return position > (getHeaderSize() + getOriginalItemSize() - 1)
    }

    private fun isHeaderPosition(position: Int): Boolean {
        return position < headers.size()
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        if (headers.indexOfKey(viewType) >= 0) {
            val headerView = headers[viewType]
            return object : RecyclerView.ViewHolder(headerView){}
        }
        if (footers.indexOfKey(viewType) >= 0) {
            val footerView = footers[viewType]
            return object : RecyclerView.ViewHolder(footerView){}
        }

        val dataItem = typeArrays.get(viewType)
        // 获取dataItem这种类型对应的视图
        var view = dataItem.getItemView(parent)
        if (null == view) {
            val layoutRes = dataItem.getItemLayoutRes()
            if (layoutRes < 0) {
                RuntimeException("dataItem:"+dataItem.javaClass.name+"应该被复写 getItemView or getItemLayoutRes")
            }
            view = mInflater!!.inflate(layoutRes, parent, false)
        }
        // 根据dataItem 通过反射取出HiDataItem<*, RecyclerView.ViewHolder>泛型中的ViewHolder实例
        return createViewHolderInternal(dataItem.javaClass, view)
    }

    private fun createViewHolderInternal(
        javaClass: Class<HiDataItem<*, out RecyclerView.ViewHolder>>,
        view: View?
    ): RecyclerView.ViewHolder {
        val superclass = javaClass.genericSuperclass
        if(superclass is ParameterizedType) {
            // 如果是参数泛型
            val arguments = superclass.actualTypeArguments // 获取泛型参数的集合
            for (argument in arguments){
                if (arguments is Class<*> && RecyclerView.ViewHolder::class.java.isAssignableFrom(
                        argument as Class<*>
                    )){
                    // 通过反射构造ViewHolder的实例
                   return argument.getConstructor(View::class.java).newInstance(view) as RecyclerView.ViewHolder
                }
            }
        }

        return object : RecyclerView.ViewHolder(view!!){}
    }

    override fun getItemCount(): Int {
        return getOriginalItemSize() + getHeaderSize() + getFooterSize()
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (isHeaderPosition(position) || isFooterPosition(position)) {
            // 因为header和footer的view是用户自行绑定的，不需要这里进行onBind
            return
        }

        val itemPos = position - getHeaderSize()
//        val hiDataItem = dataSets[itemPos] as HiDataItem<*, RecyclerView.ViewHolder>
        val hiDataItem = getItem(itemPos)
        hiDataItem?.onBindData(holder, itemPos)
    }

    // 当adapter和RecyclerView相关联的时候，会回调onAttachedToRecyclerView
    // 网格布局
    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        recyclerViewRef = WeakReference(recyclerView)

        val layoutManager = recyclerView.layoutManager
        if (layoutManager is GridLayoutManager) {
            val spanCount = layoutManager.spanCount
            layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                override fun getSpanSize(position: Int): Int {
                    if (isHeaderPosition(position) || isFooterPosition(position)) {
                        return spanCount
                    }

                    val itemPos = position - getHeaderSize()
                    if (itemPos < dataSets.size) {
                        val dataItem = dataSets[itemPos]
                        val spanSize = dataItem.getSpanSize()
                        return if (spanSize <= 0) spanCount else spanSize
                    }
                    return spanCount
                }

            }
        }
    }
    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        recyclerViewRef?.clear()
    }

    // 瀑布流布局
    override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
        val recyclerView:RecyclerView? = getAttachRecyclerView()
        recyclerView?.let {
            // 瀑布六item占比适配
            val position = recyclerView.getChildAdapterPosition(holder.itemView)
            val isHeaderFooter = isHeaderPosition(position) || isFooterPosition(position)
            val itemPos = position - getHeaderSize()
            val dataItem = getItem(itemPos) ?: return
            val lp = holder.itemView.layoutParams
            if (lp != null && lp is StaggeredGridLayoutManager.LayoutParams) {
                val manager = recyclerView.layoutManager as StaggeredGridLayoutManager?
                if (isHeaderFooter) {
                    lp.isFullSpan = true
                    return
                }
                val spanSize = dataItem.getSpanSize()
                if (spanSize == manager!!.spanCount) {
                    lp.isFullSpan = true
                }
            }
            dataItem.onViewAttachedToWindow(holder)
        }
    }
    fun getAttachRecyclerView(): RecyclerView? {
        return recyclerViewRef?.get()
    }

    override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
        val position = holder.adapterPosition
        if (isHeaderPosition(position) || isFooterPosition(position)) return
        val itemPos = position - getHeaderSize()
        val dataItem = getItem(itemPos) ?: return
        dataItem.onViewDetachedFromWindow(holder)
    }

    private fun getItem(position: Int): HiDataItem<*, ViewHolder>? {
        if (position < 0 || position >= dataSets.size)
            return null
        return dataSets[position]
    }

    fun clearItems() {
        dataSets.clear()
        notifyDataSetChanged()
    }

}